This R script is used to merge RS data downloaded the Google Drive folder shared by Bea with the ReSurvey database.

Load libraries

library(tidyverse)
library(here)
library(lubridate)
library(dtplyr)
library(sf)

Read files with RS data from Bea

S2

NDVI, NDMI & other indices

Files downloaded from folder Drive/MOTIVATE-EVEREST/1.VALIDATION/db_Europe/S2/Ene-dic

# Set the folder path
folder_path <- "C:/Data/MOTIVATE/MOTIVATE_RS_data/S2"

# List CSV files
csv_files <- list.files(folder_path, full.names = TRUE, recursive = TRUE)

# Function to extract biogeo and unit from the filename
extract_info <- function(filename) {
  first_word <- strsplit(filename, "_")[[1]][1]
  biogeo <- str_extract(first_word, "^(ALP|ARC|ATL|BOR|CON|MED|PANONIA)")
  unit <- str_remove(first_word, biogeo)
  if (unit == "") unit <- NA_character_
  list(biogeo = biogeo, unit = unit)
}


# Read and process each file
data_list <- lapply(csv_files, function(file) {
  info <- extract_info(basename(file)) # Use only the filename
  
  # Read the file
  df <- read_csv(file) %>%
    # Remove columns that give column type problems when combining data
    select(-starts_with("EUNIS"), -starts_with("ReSurvey")) %>%
    mutate(biogeo = info$biogeo, unit = info$unit)
  
  return(df)
  })
Rows: 1978 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (21): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (22): EUNISa_4, EUNISa_4_d, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EUNISc_1_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 205 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (21): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (22): EUNISa_4, EUNISa_4_d, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EUNISc_1_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 41 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 163 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
G2;H2;Avisoh: One or more parsing issues, call `problems()` on your data frame for details, e.g.:
  dat <- vroom(...)
  problems(dat)g
Rows: 5074 Columns: 90
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (47): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 922 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (20): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (51): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (22): EUNISa_4, EUNISa_4_d, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EUNISc_1_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 95 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 108 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 1417 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (21): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (22): EUNISa_4, EUNISa_4_d, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EUNISc_1_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 107 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (21): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (22): EUNISa_4, EUNISa_4_d, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EUNISc_1_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 918 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (21): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (22): EUNISa_4, EUNISa_4_d, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EUNISc_1_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 125 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
G2;H2;Avisoh: One or more parsing issues, call `problems()` on your data frame for details, e.g.:
  dat <- vroom(...)
  problems(dat)g
Rows: 1827 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 130 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 205 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 8 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (10): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, RS_CODE, ReSurvey p,...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (33): EUNISa_2_d, EUNISa_3, EUNISa_3_d, EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 8 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 1188 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (20): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (23): EUNISa_4, EUNISa_4_d, EUNISb_1, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EU...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Combine all data
data_RS_S2 <- bind_rows(data_list)

# View the resulting tibble
print(data_RS_S2)

# Counts per biogeo and unit
print(data_RS_S2 %>% count(biogeo, unit), n = 100)

Data cleaning

Keep all indices and metrics in case they are useful.

data_RS_S2 <- data_RS_S2 %>%
  # Keep the columns we need
  select(PlotObserv, biogeo, unit, year, Lat_update, Lon_update,
         starts_with("NDVI"), starts_with("NDMI"), starts_with("NDWI"),
         starts_with("EVI"), starts_with("SAVI")) %>%
  # Rename Lat and Lon, these are only kept in case there is difference with
  # those in the ReSurvey database due to updates based on Ilona's info
  rename(Lat_RS = Lat_update, Lon_RS = Lon_update) %>%
  # Same for year
  rename(year_RS = year) %>%
  # Add column source
  mutate(source = "S2")

Phenology S2

HERE: Do not use so far - wrong!

Landsat

NDVI, NDMI & other indices

# Set the folder path
folder_path <- "C:/Data/MOTIVATE/MOTIVATE_RS_data/Landsat"

# List CSV files
csv_files <- list.files(folder_path, full.names = TRUE, recursive = TRUE)

# Function to extract biogeo and unit from the filename
extract_info <- function(filename) {
  first_word <- strsplit(filename, "_")[[1]][1]
  biogeo <- str_extract(first_word, "^(ALP|ARC|ATL|BOR|CON|MED|PANONIA)")
  unit <- str_remove(first_word, biogeo)
  if (unit == "") unit <- NA_character_
  list(biogeo = biogeo, unit = unit)
}

# Read and process each file
data_list <- lapply(csv_files, function(file) {
  info <- extract_info(basename(file)) # Use only the filename
  
  # Read the file
  df <- read_csv(file) %>%
    # Remove columns that give column type problems when combining data
    select(-starts_with("EUNIS"), -starts_with("ReSurvey")) %>%
    mutate(biogeo = info$biogeo, unit = info$unit)
  
  return(df)
  })
G2;H2;Avisoh: One or more parsing issues, call `problems()` on your data frame for details, e.g.:
  dat <- vroom(...)
  problems(dat)g
Rows: 5213 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (21): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (22): EUNISa_4, EUNISa_4_d, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EUNISc_1_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 423 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (21): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (22): EUNISa_4, EUNISa_4_d, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EUNISc_1_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 138 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 51 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 117 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (21): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (22): EUNISa_4, EUNISa_4_d, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EUNISc_1_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 213 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 64 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 92 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
G2;H2;Avisoh: One or more parsing issues, call `problems()` on your data frame for details, e.g.:
  dat <- vroom(...)
  problems(dat)g
Rows: 9447 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 6438 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (21): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (22): EUNISa_4, EUNISa_4_d, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EUNISc_1_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 96 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (24): system:index, EUNISa, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (19): EUNISa_1, EUNISa_4, EUNISa_4_d, EUNISb_1, EUNISb_4, EUNISb_4_d, EUNISc_1, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 99 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 185 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 198 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (20): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (23): EUNISa_4, EUNISa_4_d, EUNISb_1, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EU...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 20 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (12): system:index, EUNISa, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (31): EUNISa_1, EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EU...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 2394 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (21): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (22): EUNISa_4, EUNISa_4_d, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EUNISc_1_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 160 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (21): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (22): EUNISa_4, EUNISa_4_d, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EUNISc_1_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
G2;H2;Avisoh: One or more parsing issues, call `problems()` on your data frame for details, e.g.:
  dat <- vroom(...)
  problems(dat)g
Rows: 2068 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (20): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (23): EUNISa_4, EUNISa_4_d, EUNISb_1, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EU...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
G2;H2;Avisoh: One or more parsing issues, call `problems()` on your data frame for details, e.g.:
  dat <- vroom(...)
  problems(dat)g
Rows: 9807 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (26): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (17): EUNISa_4, EUNISa_4_d, EUNISb_1, EUNISb_4, EUNISb_4_d, EUNISc_1, EUNISc_4, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 308 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
G2;H2;Avisoh: One or more parsing issues, call `problems()` on your data frame for details, e.g.:
  dat <- vroom(...)
  problems(dat)g
Rows: 16171 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 2239 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (20): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (23): EUNISa_4, EUNISa_4_d, EUNISb_1, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EU...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 82 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (13): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (51): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 10 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 422 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (21): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (22): EUNISa_4, EUNISa_4_d, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EUNISc_1_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 393 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 12 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (10): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, RS_CODE, ReSurvey p,...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (33): EUNISa_2_d, EUNISa_3, EUNISa_3_d, EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 9 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 5 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 37 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (13): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (51): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (29): EUNISa_4, EUNISa_4_d, EUNISb, EUNISb_1, EUNISb_1_d, EUNISb_2, EUNISb_2_d, ...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 2042 Columns: 93
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (20): system:index, EUNISa, EUNISa_1, EUNISa_1_d, EUNISa_2, EUNISa_2_d, EUNISa_3...
dbl (50): EVI_max, EVI_mean, EVI_median, EVI_min, EVI_mode, EVI_p10, EVI_p90, EVI_st...
lgl (23): EUNISa_4, EUNISa_4_d, EUNISb_1, EUNISb_4, EUNISb_4_d, EUNISc, EUNISc_1, EU...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Combine all data
data_RS_Landsat <- bind_rows(data_list)

# View the resulting tibble
print(data_RS_Landsat)

# Counts per biogeo and unit
print(data_RS_Landsat %>% count(biogeo, unit), n = 100)

Data cleaning

Keep all indices and metrics in case they are useful.

data_RS_Landsat <- data_RS_Landsat %>%
  # Keep the columns we need
  select(PlotObserv, biogeo, unit, year, Lat_update, Lon_update,
         starts_with("NDVI"), starts_with("NDMI"), starts_with("NDWI"),
         starts_with("EVI"), starts_with("SAVI")) %>%
  # Rename Lat and Lon, these are only kept in case there is difference with
  # those in the ReSurvey database due to updates based on Ilona's info
  rename(Lat_RS = Lat_update, Lon_RS = Lon_update) %>%
  # Same for year
  rename(year_RS = year) %>%
  # Add column source
  mutate(source = "Landsat")

TO ADD: Phenology Landsat

Canopy height

data_RS_CH <- read_csv(
  "C:/Data/MOTIVATE/MOTIVATE_RS_data/Canopy_Height_1m/Europe_points_CanopyHeight_1m.csv")
Rows: 425310 Columns: 8
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): system:index, .geo
dbl (6): Lat_update, Lon_update, canopy_height, obs_unique, plot_uniqu, year

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
data_RS_CH

Data cleaning CH

data_RS_CH <- data_RS_CH %>%
  # Keep the columns we need
  select(obs_unique, canopy_height)

TBD: Biomass

Read file db_Europa

In this file, there is the correspondence obs_unique - PlotObservationID.

db_Europa <- read_csv(
  here("..", "DB_first_check", "data", "clean","db_Europa_20250107.csv")
  )
Rows: 425310 Columns: 12
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (6): Country, RS_CODE, ReSurvey site, ReSurvey plot, Expert System, Location method
dbl (6): PlotObservationID, Lon_updated, Lat_updated, plot_unique_id, year, obs_uniq...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Sample db_Europa

Read file db_resurv_updated_clean

This is the ReSurvey database after updates (to be continued).

db_resurv <- read_tsv(
  here("..", "DB_first_check","data", "clean","db_resurv_updated_clean.csv"),
  col_types = cols(
    # Dynamically specify EUNIS columns as character
    .default = col_guess(),  # Default guessing for other columns
    EUNISa = col_character(),
    EUNISb = col_character(),
    EUNISc = col_character(),
    EUNISd = col_character(),
    EUNISa_1 = col_character(),
    EUNISa_2 = col_character(),
    EUNISa_3 = col_character(),
    EUNISa_4 = col_character(),
    EUNISb_1 = col_character(),
    EUNISb_2 = col_character(),
    EUNISb_3 = col_character(),
    EUNISb_4 = col_character(),
    EUNISc_1 = col_character(),
    EUNISc_2 = col_character(),
    EUNISc_3 = col_character(),
    EUNISc_4 = col_character(),
    EUNISd_1 = col_character(),
    EUNISd_2 = col_character(),
    EUNISd_3 = col_character(),
    EUNISd_4 = col_character(),
    EUNISa_1_descr = col_character(),
    EUNISb_1_descr = col_character(),
    EUNISc_1_descr = col_character(),
    EUNISd_1_descr = col_character(),
    EUNIS_assignation = col_character(),
    EUNISa_2_descr = col_character(),
    EUNISa_3_descr = col_character(),
    EUNISa_4_descr = col_character(),
    EUNISb_2_descr = col_character(),
    EUNISb_3_descr = col_character(),
    EUNISb_4_descr = col_character(),
    EUNISc_2_descr = col_character(),
    EUNISc_3_descr = col_character(),
    EUNISc_4_descr = col_character(),
    EUNISd_2_descr = col_character(),
    EUNISd_3_descr = col_character(),
    EUNISd_4_descr = col_character()
    )
  )

No parsing issues!

Get sample of ReSurvey database:

db_Europa_sample <- left_join(
  db_resurv %>%
    select(PlotObservationID, RS_CODE, `ReSurvey site`, `ReSurvey plot`,
           Lon_updated,Lat_updated, year,date,
           starts_with("EUNIS"), `Location method`) %>%
    select(-EUNIS_assignation),
  db_Europa %>%
    select(PlotObservationID, Lon_updated, Lat_updated, year, obs_unique_id)
)
Joining with `by = join_by(PlotObservationID, Lon_updated, Lat_updated, year)`
  
print(db_Europa_sample, width = Inf)

Add column PLOT to data to identify unique plots:

db_Europa_sample <- db_Europa_sample %>%
  # Original names give problems, create new vars
  mutate(RS_site = `ReSurvey site`, RS_plot = `ReSurvey plot`) %>%
  # Convert to data.table for faster processing
  lazy_dt() %>%
  # Group by the 3 vars that uniquely identify each plot
  group_by(RS_CODE, RS_site, RS_plot) %>%
  # Create a new variable PLOT for each group
  mutate(PLOT = .GRP) %>%
  # Convert back to tibble
  as_tibble() %>%
  # Remove unneeded vars
  select(-RS_site, -RS_plot)

Keep only habitats F, R, S and Q, and, for each PLOT, keep only the last resurvey:

db_Europa_sample_latest <- db_Europa_sample %>%
  filter(EUNISa_1 %in% c("T", "R", "S", "Q")) %>%
  group_by(PLOT) %>%
  filter(date == max(date)) %>%
  ungroup()

Save as csv for Bea:

write_csv(db_Europa_sample_latest,
          file = "data/clean/db_Europa_sample_latest.csv")

Save as shp to merge with bioregions:

# # Convert to sf object
# db_Europa_sample_latest_sf <- st_as_sf(db_Europa_sample_latest,
#                                        coords = c("Lon_updated", "Lat_updated"), 
#                                        crs = 4326) # WGS84
# st_write(db_Europa_sample_latest_sf,
#          "C:/GIS/MOTIVATE/shapefiles/db_Europa_sample_latest_sf.shp")

Merge RS data and db_Europa_sample_latest

Get only the columns PlotObservationID (original unique identifier) and obs_unique_id (unique identified created by me).

db_Europa_sample_latest <- db_Europa_sample_latest %>%
  select(PlotObservationID, obs_unique_id)
data_RS_S2_ID <- db_Europa_sample_latest %>%
  right_join(data_RS_S2 %>%
               # Rename to be able to join on this column
               rename(PlotObservationID = PlotObserv))
Joining with `by = join_by(PlotObservationID)`

Now we have PlotObservationID in data_RS_S2_ID.

# data_RS_S2_phen_ID <- db_Europa_sample_latest %>%
#   right_join(data_RS_S2_phen %>%
#               # Rename to be able to join on this column
#                rename(PlotObservationID = PlotObserv))

Now we have PlotObservationID in data_RS_S2_phen_ID

data_RS_Landsat_ID <- db_Europa_sample_latest %>%
  right_join(data_RS_Landsat %>%
               # Rename to be able to join on this column
               rename(PlotObservationID = PlotObserv))
Joining with `by = join_by(PlotObservationID)`

Now we have PlotObservationID in data_RS_Landsat_ID.

data_RS_CH_ID <- db_Europa %>%
  select(PlotObservationID, obs_unique_id) %>%
  right_join(data_RS_CH %>%
              # Rename to be able to join on this column
              rename(obs_unique_id = obs_unique))
Joining with `by = join_by(obs_unique_id)`

Now we have PlotObservationID in data_RS_CH_ID.

Merge RS data to the ReSurvey database

For some points, there is data both from S2 and Landsat. In those cases, use the S2 data because it is more precise (10 m vs 30 m).

data_RS_S2_ID <- data_RS_S2_ID %>%
  rename_with(~ paste0(., "_S2"), starts_with("NDVI")) %>%
  rename_with(~ paste0(., "_S2"), starts_with("NDMI")) %>%
  rename_with(~ paste0(., "_S2"), starts_with("NDWI")) %>%
  rename_with(~ paste0(., "_S2"), starts_with("EVI")) %>%
  rename_with(~ paste0(., "_S2"), starts_with("SAVI")) %>%
  select(-source)
data_RS_Landsat_ID <- data_RS_Landsat_ID %>%
  rename_with(~ paste0(., "_Landsat"), starts_with("NDVI")) %>%
  rename_with(~ paste0(., "_Landsat"), starts_with("NDMI")) %>%
  rename_with(~ paste0(., "_Landsat"), starts_with("NDWI")) %>%
  rename_with(~ paste0(., "_Landsat"), starts_with("EVI")) %>%
  rename_with(~ paste0(., "_Landsat"), starts_with("SAVI")) %>%
  select(-source)

Join S2, S2_phen and Landsat data:

data_RS <- data_RS_S2_ID %>% 
  # full_join(data_RS_S2_phen_ID) %>%
  full_join(data_RS_Landsat_ID)
Joining with `by = join_by(PlotObservationID, obs_unique_id, biogeo, unit, year_RS,
Lat_RS, Lon_RS)`

Number of observations with NDVI_max data from both S2 and Landsat:

nrow(data_RS %>% filter(!is.na(NDVI_max_S2) & !is.na(NDVI_max_Landsat)))
[1] 14518

Difference between NDVI_max values from S2 and Landsat:

data_RS %>% filter(!is.na(NDVI_max_S2) & !is.na(NDVI_max_Landsat)) %>%
  mutate(diff_NDVI_max = abs(NDVI_max_S2 - NDVI_max_Landsat)) %>%
  ggplot(aes(x = diff_NDVI_max, fill = paste(biogeo, unit, sep = "-"))) +
  geom_histogram(color = "black") + 
  facet_wrap(~ paste(biogeo, unit, sep = "-")) + theme(legend.position = "none")

data_RS %>% filter(!is.na(NDMI_max_S2) & !is.na(NDMI_max_Landsat)) %>%
  mutate(diff_NDMI_max = abs(NDMI_max_S2 - NDMI_max_Landsat)) %>%
  ggplot(aes(x = diff_NDMI_max, fill = paste(biogeo, unit, sep = "-"))) +
  geom_histogram(color = "black") + 
  facet_wrap(~ paste(biogeo, unit, sep = "-")) + theme(legend.position = "none")

There is a large difference between NDVI values from S2 and Landsat. So far, use the S2 data, but checking with Bea / Jose.

When values are available from both satellites, use S2:

data_RS <- data_RS %>%
  mutate(across(
    matches("^(NDVI|NDMI|NDWI|EVI|SAVI)_(max|mean|median|min|mode|p10|p90|stdDev)_S2$"),
    ~ case_when(
      # If both the current column and the corresponding Landsat column are NA,
      # set to NA_real_
      is.na(.x) & is.na(get(sub("_S2$", "_Landsat", cur_column()))) ~ NA_real_,
      # If the corresponding Landsat column is NA, use the current column's value
      is.na(get(sub("_S2$", "_Landsat", cur_column()))) ~ .x,
      # If the current column is NA, use the corresponding Landsat column's value
      is.na(.x) ~ get(sub("_S2$", "_Landsat", cur_column())),
      # Otherwise, use the current column's value
      TRUE ~ .x
      ), .names = "{col}_combined")) %>%
  rename_with(~ sub("_S2_combined$", "", .), matches("_S2_combined$"))

Get number of points per biogeo and unit:

npoints_bioregion_R <- data_RS %>% count(biogeo, unit) %>%
  mutate(npoints_R = n) %>%
  select(-n)

Read number of points per biogeo and unit from GIS:

npoints_bioregion_GIS <- read_delim(
  "data/clean/Npoints_bioregion.csv", delim = ";"
  ) %>%
  select (BIOGEO, UNIT, Join_Count) %>%
  mutate(biogeo = BIOGEO, unit = str_remove(UNIT, BIOGEO),
         npoints_GIS = Join_Count) %>%
  mutate(biogeo = ifelse(biogeo == "PAN", "PANONIA", biogeo)) %>%
  mutate(unit = ifelse(biogeo == "PANONIA", NA, unit)) %>%
  select(- BIOGEO, - UNIT, -Join_Count)
Rows: 42 Columns: 54
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ";"
chr (44): name, BIOGEO, UNIT, RS_CODE, RSrvyst, RSrvypl, date, EUNISa, EUNISb, EUNIS...
dbl  (5): OID_, Join_Count, TARGET_FID, code, PLOT
num  (5): AREA, PltObID, year, Shape_Length, Shape_Area

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Merge both and see differences in n points:

npoints_bioregion_merged <- full_join(npoints_bioregion_R,
                                      npoints_bioregion_GIS)
Joining with `by = join_by(biogeo, unit)`

Nice table to email to Bea:

kable(print(npoints_bioregion_merged %>% arrange(biogeo, unit), n = 100))
biogeo unit npoints_R npoints_GIS
ALP ALPS 5214 5360
ALP ATRA 423 423
ALP BALKAN 138 138
ALP DINARIC NA 0
ALP ENNINE 51 54
ALP NORDIC 117 117
ALP PYR 213 213
ALP ROMANIAN 64 64
ANA TURKEY NA 0
ARC ICELAND NA 0
ARC NORWAY 92 106
ATL BENELUX 9447 9530
ATL BRITAIN 6438 6761
ATL FRANCE 96 97
ATL IBERIA 99 99
ATL IRELAND NA 0
ATL NORDIC NA 0
BLS BLACKSEA NA 0
BOR BALTIC 185 185
BOR FINLAND 198 240
BOR NORDIC 20 20
CON AUSTRIA 2394 2439
CON BALKAN 160 160
CON FRANCE 2068 2091
CON GERMANY 9807 9924
CON ITALICA 308 312
CON NORDIC 16171 16172
CON POLAND 2239 2241
CON ROMANIA 82 82
MAC ARONESIA NA 0
MED BALEAR NA 0
MED BALKAN NA 0
MED FRANCE NA 0
MED GREECE 10 10
MED IBERIA 422 422
MED ITALICA 393 395
MED PORT 12 12
MED SICILIA 9 9
MED TIRRENO 5 5
MED TURKEY 37 37
PANONIA NA 2042 2046
STE PPIC NA 0
db_resurv_RS <- db_resurv %>%
  left_join(data_RS %>% select(-obs_unique_id)) %>%
  left_join(data_RS_CH_ID %>% select(-obs_unique_id)) %>%
  mutate(S2_data = !is.na(NDVI_max_S2) & !is.na(NDMI_max_S2), 
         Landsat_data = !is.na(NDVI_max_Landsat) & !is.na(NDMI_max_Landsat),
         S2_or_Landsat_data = !is.na(NDVI_max) & !is.na(NDMI_max), 
         # S2_phen_data = !is.na(SOS_DOY),
         CH_data = !is.na(canopy_height)) %>%
  # So far, remove cols for _S2 and _Landsat
  select(-matches("_(S2|Landsat)$"))
Joining with `by = join_by(PlotObservationID)`
Joining with `by = join_by(PlotObservationID)`
db_resurv_RS %>% count(S2_data)
db_resurv_RS %>% count(Landsat_data)
db_resurv_RS %>% count(S2_or_Landsat_data)
db_resurv_RS %>% count(CH_data)
# db_resurv_RS %>% count(S2_phen_data)

Save to clean data

Save clean file for analyses (to be updated continuously due to updates in ReSurvey database and updates on RS data).

write_tsv(db_resurv_RS,here("data", "clean","db_resurv_RS_20250610.csv"))

Session info

sessionInfo()
R version 4.5.0 (2025-04-11 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 11 x64 (build 26100)

Matrix products: default
  LAPACK version 3.12.1

locale:
[1] LC_COLLATE=Spanish_Spain.utf8  LC_CTYPE=Spanish_Spain.utf8   
[3] LC_MONETARY=Spanish_Spain.utf8 LC_NUMERIC=C                  
[5] LC_TIME=Spanish_Spain.utf8    

time zone: Europe/Madrid
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] knitr_1.50      sf_1.0-20       dtplyr_1.3.1    here_1.0.1      lubridate_1.9.4
 [6] forcats_1.0.0   stringr_1.5.1   dplyr_1.1.4     purrr_1.0.4     readr_2.1.5    
[11] tidyr_1.3.1     tibble_3.2.1    ggplot2_3.5.2   tidyverse_2.0.0

loaded via a namespace (and not attached):
 [1] sass_0.4.10        utf8_1.2.5         generics_0.1.4     class_7.3-23      
 [5] KernSmooth_2.23-26 stringi_1.8.7      hms_1.1.3          digest_0.6.37     
 [9] magrittr_2.0.3     evaluate_1.0.3     grid_4.5.0         timechange_0.3.0  
[13] RColorBrewer_1.1-3 fastmap_1.2.0      rprojroot_2.0.4    jsonlite_2.0.0    
[17] e1071_1.7-16       DBI_1.2.3          scales_1.4.0       jquerylib_0.1.4   
[21] cli_3.6.5          rlang_1.1.6        crayon_1.5.3       units_0.8-7       
[25] bit64_4.6.0-1      withr_3.0.2        cachem_1.1.0       yaml_2.3.10       
[29] tools_4.5.0        parallel_4.5.0     tzdb_0.5.0         vctrs_0.6.5       
[33] R6_2.6.1           proxy_0.4-27       classInt_0.4-11    lifecycle_1.0.4   
[37] bit_4.6.0          vroom_1.6.5        pkgconfig_2.0.3    pillar_1.10.2     
[41] bslib_0.9.0        gtable_0.3.6       Rcpp_1.0.14        data.table_1.17.2 
[45] glue_1.8.0         xfun_0.52          tidyselect_1.2.1   rstudioapi_0.17.1 
[49] farver_2.1.2       htmltools_0.5.8.1  labeling_0.4.3     rmarkdown_2.29    
[53] compiler_4.5.0    
LS0tDQp0aXRsZTogIlNjcmlwdCB0byBtZXJnZSBhbGwgUlMgZGF0YSINCmF1dGhvcjogIkFsaWNpYSBWYWxkw6lzIg0KZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIgJVknKWAiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpUaGlzIFIgc2NyaXB0IGlzIHVzZWQgdG8gbWVyZ2UgUlMgZGF0YSBkb3dubG9hZGVkIHRoZSBHb29nbGUgRHJpdmUgZm9sZGVyIHNoYXJlZCBieSBCZWEgd2l0aCB0aGUgUmVTdXJ2ZXkgZGF0YWJhc2UuDQoNCiMgTG9hZCBsaWJyYXJpZXMNCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoaGVyZSkNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShkdHBseXIpDQpsaWJyYXJ5KHNmKQ0KYGBgDQoNCiMgUmVhZCBmaWxlcyB3aXRoIFJTIGRhdGEgZnJvbSBCZWENCg0KIyMgUzIgDQoNCiMjIyBORFZJLCBORE1JICYgb3RoZXIgaW5kaWNlcw0KDQpGaWxlcyBkb3dubG9hZGVkIGZyb20gZm9sZGVyIERyaXZlL01PVElWQVRFLUVWRVJFU1QvMS5WQUxJREFUSU9OL2RiX0V1cm9wZS9TMi9FbmUtZGljDQoNCmBgYHtyfQ0KIyBTZXQgdGhlIGZvbGRlciBwYXRoDQpmb2xkZXJfcGF0aCA8LSAiQzovRGF0YS9NT1RJVkFURS9NT1RJVkFURV9SU19kYXRhL1MyIg0KDQojIExpc3QgQ1NWIGZpbGVzDQpjc3ZfZmlsZXMgPC0gbGlzdC5maWxlcyhmb2xkZXJfcGF0aCwgZnVsbC5uYW1lcyA9IFRSVUUsIHJlY3Vyc2l2ZSA9IFRSVUUpDQoNCiMgRnVuY3Rpb24gdG8gZXh0cmFjdCBiaW9nZW8gYW5kIHVuaXQgZnJvbSB0aGUgZmlsZW5hbWUNCmV4dHJhY3RfaW5mbyA8LSBmdW5jdGlvbihmaWxlbmFtZSkgew0KICBmaXJzdF93b3JkIDwtIHN0cnNwbGl0KGZpbGVuYW1lLCAiXyIpW1sxXV1bMV0NCiAgYmlvZ2VvIDwtIHN0cl9leHRyYWN0KGZpcnN0X3dvcmQsICJeKEFMUHxBUkN8QVRMfEJPUnxDT058TUVEfFBBTk9OSUEpIikNCiAgdW5pdCA8LSBzdHJfcmVtb3ZlKGZpcnN0X3dvcmQsIGJpb2dlbykNCiAgaWYgKHVuaXQgPT0gIiIpIHVuaXQgPC0gTkFfY2hhcmFjdGVyXw0KICBsaXN0KGJpb2dlbyA9IGJpb2dlbywgdW5pdCA9IHVuaXQpDQp9DQoNCg0KIyBSZWFkIGFuZCBwcm9jZXNzIGVhY2ggZmlsZQ0KZGF0YV9saXN0IDwtIGxhcHBseShjc3ZfZmlsZXMsIGZ1bmN0aW9uKGZpbGUpIHsNCiAgaW5mbyA8LSBleHRyYWN0X2luZm8oYmFzZW5hbWUoZmlsZSkpICMgVXNlIG9ubHkgdGhlIGZpbGVuYW1lDQogIA0KICAjIFJlYWQgdGhlIGZpbGUNCiAgZGYgPC0gcmVhZF9jc3YoZmlsZSkgJT4lDQogICAgIyBSZW1vdmUgY29sdW1ucyB0aGF0IGdpdmUgY29sdW1uIHR5cGUgcHJvYmxlbXMgd2hlbiBjb21iaW5pbmcgZGF0YQ0KICAgIHNlbGVjdCgtc3RhcnRzX3dpdGgoIkVVTklTIiksIC1zdGFydHNfd2l0aCgiUmVTdXJ2ZXkiKSkgJT4lDQogICAgbXV0YXRlKGJpb2dlbyA9IGluZm8kYmlvZ2VvLCB1bml0ID0gaW5mbyR1bml0KQ0KICANCiAgcmV0dXJuKGRmKQ0KICB9KQ0KDQojIENvbWJpbmUgYWxsIGRhdGENCmRhdGFfUlNfUzIgPC0gYmluZF9yb3dzKGRhdGFfbGlzdCkNCg0KIyBWaWV3IHRoZSByZXN1bHRpbmcgdGliYmxlDQpwcmludChkYXRhX1JTX1MyKQ0KDQojIENvdW50cyBwZXIgYmlvZ2VvIGFuZCB1bml0DQpwcmludChkYXRhX1JTX1MyICU+JSBjb3VudChiaW9nZW8sIHVuaXQpLCBuID0gMTAwKQ0KYGBgDQoNCiMjIyMgRGF0YSBjbGVhbmluZw0KDQpLZWVwIGFsbCBpbmRpY2VzIGFuZCBtZXRyaWNzIGluIGNhc2UgdGhleSBhcmUgdXNlZnVsLg0KDQpgYGB7cn0NCmRhdGFfUlNfUzIgPC0gZGF0YV9SU19TMiAlPiUNCiAgIyBLZWVwIHRoZSBjb2x1bW5zIHdlIG5lZWQNCiAgc2VsZWN0KFBsb3RPYnNlcnYsIGJpb2dlbywgdW5pdCwgeWVhciwgTGF0X3VwZGF0ZSwgTG9uX3VwZGF0ZSwNCiAgICAgICAgIHN0YXJ0c193aXRoKCJORFZJIiksIHN0YXJ0c193aXRoKCJORE1JIiksIHN0YXJ0c193aXRoKCJORFdJIiksDQogICAgICAgICBzdGFydHNfd2l0aCgiRVZJIiksIHN0YXJ0c193aXRoKCJTQVZJIikpICU+JQ0KICAjIFJlbmFtZSBMYXQgYW5kIExvbiwgdGhlc2UgYXJlIG9ubHkga2VwdCBpbiBjYXNlIHRoZXJlIGlzIGRpZmZlcmVuY2Ugd2l0aA0KICAjIHRob3NlIGluIHRoZSBSZVN1cnZleSBkYXRhYmFzZSBkdWUgdG8gdXBkYXRlcyBiYXNlZCBvbiBJbG9uYSdzIGluZm8NCiAgcmVuYW1lKExhdF9SUyA9IExhdF91cGRhdGUsIExvbl9SUyA9IExvbl91cGRhdGUpICU+JQ0KICAjIFNhbWUgZm9yIHllYXINCiAgcmVuYW1lKHllYXJfUlMgPSB5ZWFyKSAlPiUNCiAgIyBBZGQgY29sdW1uIHNvdXJjZQ0KICBtdXRhdGUoc291cmNlID0gIlMyIikNCmBgYA0KDQojIyMgUGhlbm9sb2d5IFMyDQoNCiMjIyMgSEVSRTogRG8gbm90IHVzZSBzbyBmYXIgLSB3cm9uZyENCg0KPCEtLSBNYW51YWxseSByZW5hbWVkIGFsbCBmaWxlcyBhcyBSRUdJT05fU1VCUkVHSU9OX1BoZW5vbG9neS4gLS0+DQoNCjwhLS0gYGBge3J9IC0tPg0KPCEtLSAjIFNldCB0aGUgZm9sZGVyIHBhdGggLS0+DQo8IS0tIGZvbGRlcl9wYXRoIDwtICJDOi9EYXRhL01PVElWQVRFL01PVElWQVRFX1JTX2RhdGEvUzIiIC0tPg0KDQo8IS0tICMgTGlzdCBvbmx5IENTViBmaWxlcyB0aGF0IGNvbnRhaW4gIlBoZW5vbG9neSIgaW4gdGhlaXIgZmlsZW5hbWUgLS0+DQo8IS0tIGNzdl9maWxlcyA8LSBsaXN0LmZpbGVzKGZvbGRlcl9wYXRoLCBwYXR0ZXJuID0gIlBoZW5vbG9neS4qXFwuY3N2JCIsIC0tPg0KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVFJVRSwgcmVjdXJzaXZlID0gVFJVRSkgLS0+DQoNCjwhLS0gIyBGdW5jdGlvbiB0byByZWFkIGVhY2ggZmlsZSBhbmQgZXh0cmFjdCBpbmZvIGZyb20gdGhlIGZpbGVuYW1lIC0tPg0KPCEtLSByZWFkX2FuZF9sYWJlbCA8LSBmdW5jdGlvbihmaWxlX3BhdGgpIHsgLS0+DQo8IS0tICAgZmlsZV9uYW1lIDwtIGJhc2VuYW1lKGZpbGVfcGF0aCkgLS0+DQoNCjwhLS0gICAjIEV4dHJhY3QgcmVnaW9uIGFuZCBzdWJyZWdpb24gZnJvbSB0aGUgZmlsZW5hbWUgLS0+DQo8IS0tICAgIyBVcGRhdGVkIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBoYW5kbGUgdGhlIGNhc2Ugd2hlcmUgc3VicmVnaW9uIGlzIG1pc3NpbmcgLS0+DQo8IS0tICAgY29tcG9uZW50cyA8LSBzdHJfbWF0Y2goZmlsZV9uYW1lLCAtLT4NCjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAiXlswLTlfXSooW15fXSspXyhbXl9dKylfUGhlbm9sb2d5LmNzdiIpIC0tPg0KDQo8IS0tICAgIyBFeHRyYWN0IHRoZSBiaW9nZW8gYW5kIHVuaXQsIGhhbmRsaW5nIG1pc3Npbmcgc3VicmVnaW9uICh1bml0KSAtLT4NCjwhLS0gICBiaW9nZW8gPC0gY29tcG9uZW50c1syXSAtLT4NCg0KPCEtLSAgICMgSWYgc3VicmVnaW9uICh1bml0KSBpcyBtaXNzaW5nLCBzZXQgaXQgYXMgTkEgLS0+DQo8IS0tICAgdW5pdCA8LSBpZmVsc2UoaXMubmEoY29tcG9uZW50c1szXSksIE5BLCBjb21wb25lbnRzWzNdKSAtLT4NCg0KPCEtLSAgICMgQ2hlY2sgaWYgYmlvZ2VvIGlzIG1pc3NpbmcsIGFuZCBpZiBzbywgLS0+DQo8IS0tICAgIyBhc3NpZ24gdGhlIGZpcnN0IHBhcnQgb2YgdGhlIGZpbGVuYW1lIChyZWdpb24gbmFtZSkgLS0+DQo8IS0tICAgaWYgKGlzLm5hKGJpb2dlbykgJiYgZ3JlcGwoIl9QaGVub2xvZ3kiLCBmaWxlX25hbWUpKSB7IC0tPg0KPCEtLSAgICAgIyBDYXB0dXJlIHRoZSBmaXJzdCBwYXJ0IChiaW9nZW8pIGRpcmVjdGx5IC0tPg0KPCEtLSAgICAgYmlvZ2VvIDwtIHN0cl9tYXRjaChmaWxlX25hbWUsICJeWzAtOV9dKihbXl9dKylfUGhlbm9sb2d5IilbMl0gLS0+DQo8IS0tICAgfSAtLT4NCg0KPCEtLSAgICMgSWYgYmlvZ2VvIGlzIHN0aWxsIE5BLCBwcmludCBhIHdhcm5pbmcgLS0+DQo8IS0tICAgaWYgKGlzLm5hKGJpb2dlbykpIHsgLS0+DQo8IS0tICAgICB3YXJuaW5nKHBhc3RlKCJGYWlsZWQgdG8gZXh0cmFjdCBiaW9nZW8gZm9yIGZpbGU6IiwgZmlsZV9uYW1lKSkgLS0+DQo8IS0tICAgfSAtLT4NCg0KPCEtLSAgICMgUmVhZCBDU1YgYW5kIGFkZCBjb2x1bW5zIGZvciBleHRyYWN0ZWQgaW5mbyAtLT4NCjwhLS0gICByZWFkX2NzdihmaWxlX3BhdGgpICU+JSAtLT4NCjwhLS0gICAgIG11dGF0ZShiaW9nZW8gPSBiaW9nZW8sIHVuaXQgPSB1bml0KSAtLT4NCjwhLS0gfSAtLT4NCjwhLS0gIyBSZWFkIGFuZCBtZXJnZSBhbGwgQ1NWIGZpbGVzIC0tPg0KPCEtLSBkYXRhX1JTX1MyX3BoZW4gPC0gbWFwX2Rmcihjc3ZfZmlsZXMsIHJlYWRfYW5kX2xhYmVsKSAtLT4NCg0KPCEtLSAjIFZpZXcgdGhlIHJlc3VsdGluZyB0aWJibGUgLS0+DQo8IS0tIHByaW50KGRhdGFfUlNfUzJfcGhlbikgLS0+DQoNCjwhLS0gIyBDb3VudHMgcGVyIGJpb2dlbyBhbmQgdW5pdCAtLT4NCjwhLS0gcHJpbnQoZGF0YV9SU19TMl9waGVuICU+JSBjb3VudChiaW9nZW8sIHVuaXQpLCBuID0gMTAwKSAtLT4NCjwhLS0gYGBgIC0tPg0KDQo8IS0tICMjIyMgRGF0YSBjbGVhbmluZyAtLT4NCg0KPCEtLSBgYGB7cn0gLS0+DQo8IS0tIGRhdGFfUlNfUzJfcGhlbiA8LSBkYXRhX1JTX1MyX3BoZW4gJT4lIC0tPg0KPCEtLSAgICMgS2VlcCB0aGUgY29sdW1ucyB3ZSBuZWVkOiAtLT4NCjwhLS0gICAjIERhdGVzIHdlcmUgd3JvbmdseSBleHBvcnRlZCBmcm9tIEdFRSAtIHJlbW92ZWQgdGhlbSBhbmQgcmVjYWxjdWxhdGVkIGxhdGVyLiAtLT4NCjwhLS0gICAjIFJlbW92ZSBMYXQgYW5kIExvbiBhbmQgeWVhciwgaW4gY2FzZSB0aGVyZSBpcyBkaWZmZXJlbmNlIHdpdGggLS0+DQo8IS0tICAgIyB0aG9zZSBpbiB0aGUgUmVTdXJ2ZXkgZGF0YWJhc2UgZHVlIHRvIHVwZGF0ZXMgYmFzZWQgb24gSWxvbmEncyBpbmZvLCAtLT4NCjwhLS0gICAjIHdlIGhhdmUgTGF0X1JTLCBMb25fUlMgYW5kIHllYXJfUlMgZnJvbSBkYXRhX1JTX1MyIC0tPg0KPCEtLSAgIHNlbGVjdChvYnNfdW5pcXVlLCBiaW9nZW8sIHVuaXQsIFNPU19ET1ksIE5EVklfYXRfU09TLCBQZWFrX0RPWSwgTkRWSV9hdF9QZWFrLCAtLT4NCjwhLS0gICAgICAgICAgRU9TX0RPWSwgTkRWSV9hdF9FT1MsIFNlYXNvbl9MZW5ndGgsIHllYXIpICU+JSAtLT4NCjwhLS0gICAjIG1ha2VfZGF0ZSgpIGNyZWF0ZXMgYSBkYXRlIGF0IHRoZSBzdGFydCBvZiB0aGUgeWVhciAoSmFudWFyeSAxc3QpLiAgLS0+DQo8IS0tICAgIyBCeSBhZGRpbmcgZGF5cyhET1kgLSAxKSwgd2UgY29ycmVjdGx5IHBvc2l0aW9uIHRoZSBkYXRlIHdpdGhpbiB0aGUgeWVhci4gLS0+DQo8IS0tICAgbXV0YXRlKFNPU19kYXRlID0gbWFrZV9kYXRlKHllYXIpICsgZGF5cyhTT1NfRE9ZIC0gMSksIC0tPg0KPCEtLSAgICAgICAgICBQZWFrX2RhdGUgPSBtYWtlX2RhdGUoeWVhcikgKyBkYXlzKFBlYWtfRE9ZIC0gMSksIC0tPg0KPCEtLSAgICAgICAgICBFT1NfZGF0ZSA9IG1ha2VfZGF0ZSh5ZWFyKSArIGRheXMoRU9TX0RPWSAtIDEpKSAlPiUgLS0+DQo8IS0tICAgIyBSZW1vdmUgeWVhciAtLT4NCjwhLS0gICBzZWxlY3QoLXllYXIpIC0tPg0KPCEtLSBgYGAgLS0+DQoNCiMjIExhbmRzYXQNCg0KIyMjIE5EVkksIE5ETUkgJiBvdGhlciBpbmRpY2VzDQoNCmBgYHtyfQ0KIyBTZXQgdGhlIGZvbGRlciBwYXRoDQpmb2xkZXJfcGF0aCA8LSAiQzovRGF0YS9NT1RJVkFURS9NT1RJVkFURV9SU19kYXRhL0xhbmRzYXQiDQoNCiMgTGlzdCBDU1YgZmlsZXMNCmNzdl9maWxlcyA8LSBsaXN0LmZpbGVzKGZvbGRlcl9wYXRoLCBmdWxsLm5hbWVzID0gVFJVRSwgcmVjdXJzaXZlID0gVFJVRSkNCg0KIyBGdW5jdGlvbiB0byBleHRyYWN0IGJpb2dlbyBhbmQgdW5pdCBmcm9tIHRoZSBmaWxlbmFtZQ0KZXh0cmFjdF9pbmZvIDwtIGZ1bmN0aW9uKGZpbGVuYW1lKSB7DQogIGZpcnN0X3dvcmQgPC0gc3Ryc3BsaXQoZmlsZW5hbWUsICJfIilbWzFdXVsxXQ0KICBiaW9nZW8gPC0gc3RyX2V4dHJhY3QoZmlyc3Rfd29yZCwgIl4oQUxQfEFSQ3xBVEx8Qk9SfENPTnxNRUR8UEFOT05JQSkiKQ0KICB1bml0IDwtIHN0cl9yZW1vdmUoZmlyc3Rfd29yZCwgYmlvZ2VvKQ0KICBpZiAodW5pdCA9PSAiIikgdW5pdCA8LSBOQV9jaGFyYWN0ZXJfDQogIGxpc3QoYmlvZ2VvID0gYmlvZ2VvLCB1bml0ID0gdW5pdCkNCn0NCg0KIyBSZWFkIGFuZCBwcm9jZXNzIGVhY2ggZmlsZQ0KZGF0YV9saXN0IDwtIGxhcHBseShjc3ZfZmlsZXMsIGZ1bmN0aW9uKGZpbGUpIHsNCiAgaW5mbyA8LSBleHRyYWN0X2luZm8oYmFzZW5hbWUoZmlsZSkpICMgVXNlIG9ubHkgdGhlIGZpbGVuYW1lDQogIA0KICAjIFJlYWQgdGhlIGZpbGUNCiAgZGYgPC0gcmVhZF9jc3YoZmlsZSkgJT4lDQogICAgIyBSZW1vdmUgY29sdW1ucyB0aGF0IGdpdmUgY29sdW1uIHR5cGUgcHJvYmxlbXMgd2hlbiBjb21iaW5pbmcgZGF0YQ0KICAgIHNlbGVjdCgtc3RhcnRzX3dpdGgoIkVVTklTIiksIC1zdGFydHNfd2l0aCgiUmVTdXJ2ZXkiKSkgJT4lDQogICAgbXV0YXRlKGJpb2dlbyA9IGluZm8kYmlvZ2VvLCB1bml0ID0gaW5mbyR1bml0KQ0KICANCiAgcmV0dXJuKGRmKQ0KICB9KQ0KDQojIENvbWJpbmUgYWxsIGRhdGENCmRhdGFfUlNfTGFuZHNhdCA8LSBiaW5kX3Jvd3MoZGF0YV9saXN0KQ0KDQojIFZpZXcgdGhlIHJlc3VsdGluZyB0aWJibGUNCnByaW50KGRhdGFfUlNfTGFuZHNhdCkNCg0KIyBDb3VudHMgcGVyIGJpb2dlbyBhbmQgdW5pdA0KcHJpbnQoZGF0YV9SU19MYW5kc2F0ICU+JSBjb3VudChiaW9nZW8sIHVuaXQpLCBuID0gMTAwKQ0KYGBgDQoNCiMjIyMgRGF0YSBjbGVhbmluZw0KDQpLZWVwIGFsbCBpbmRpY2VzIGFuZCBtZXRyaWNzIGluIGNhc2UgdGhleSBhcmUgdXNlZnVsLg0KDQpgYGB7cn0NCmRhdGFfUlNfTGFuZHNhdCA8LSBkYXRhX1JTX0xhbmRzYXQgJT4lDQogICMgS2VlcCB0aGUgY29sdW1ucyB3ZSBuZWVkDQogIHNlbGVjdChQbG90T2JzZXJ2LCBiaW9nZW8sIHVuaXQsIHllYXIsIExhdF91cGRhdGUsIExvbl91cGRhdGUsDQogICAgICAgICBzdGFydHNfd2l0aCgiTkRWSSIpLCBzdGFydHNfd2l0aCgiTkRNSSIpLCBzdGFydHNfd2l0aCgiTkRXSSIpLA0KICAgICAgICAgc3RhcnRzX3dpdGgoIkVWSSIpLCBzdGFydHNfd2l0aCgiU0FWSSIpKSAlPiUNCiAgIyBSZW5hbWUgTGF0IGFuZCBMb24sIHRoZXNlIGFyZSBvbmx5IGtlcHQgaW4gY2FzZSB0aGVyZSBpcyBkaWZmZXJlbmNlIHdpdGgNCiAgIyB0aG9zZSBpbiB0aGUgUmVTdXJ2ZXkgZGF0YWJhc2UgZHVlIHRvIHVwZGF0ZXMgYmFzZWQgb24gSWxvbmEncyBpbmZvDQogIHJlbmFtZShMYXRfUlMgPSBMYXRfdXBkYXRlLCBMb25fUlMgPSBMb25fdXBkYXRlKSAlPiUNCiAgIyBTYW1lIGZvciB5ZWFyDQogIHJlbmFtZSh5ZWFyX1JTID0geWVhcikgJT4lDQogICMgQWRkIGNvbHVtbiBzb3VyY2UNCiAgbXV0YXRlKHNvdXJjZSA9ICJMYW5kc2F0IikNCmBgYA0KDQojIyMgVE8gQUREOiBQaGVub2xvZ3kgTGFuZHNhdA0KDQojIyBDYW5vcHkgaGVpZ2h0DQoNCmBgYHtyfQ0KZGF0YV9SU19DSCA8LSByZWFkX2NzdigNCiAgIkM6L0RhdGEvTU9USVZBVEUvTU9USVZBVEVfUlNfZGF0YS9DYW5vcHlfSGVpZ2h0XzFtL0V1cm9wZV9wb2ludHNfQ2Fub3B5SGVpZ2h0XzFtLmNzdiIpDQpkYXRhX1JTX0NIDQpgYGANCg0KIyMjIERhdGEgY2xlYW5pbmcgQ0gNCg0KYGBge3J9DQpkYXRhX1JTX0NIIDwtIGRhdGFfUlNfQ0ggJT4lDQogICMgS2VlcCB0aGUgY29sdW1ucyB3ZSBuZWVkDQogIHNlbGVjdChvYnNfdW5pcXVlLCBjYW5vcHlfaGVpZ2h0KQ0KYGBgDQoNCiMjIFRCRDogQmlvbWFzcw0KDQojIFJlYWQgZmlsZSBkYl9FdXJvcGENCg0KSW4gdGhpcyBmaWxlLCB0aGVyZSBpcyB0aGUgY29ycmVzcG9uZGVuY2Ugb2JzX3VuaXF1ZSAtIFBsb3RPYnNlcnZhdGlvbklELg0KDQpgYGB7cn0NCmRiX0V1cm9wYSA8LSByZWFkX2NzdigNCiAgaGVyZSgiLi4iLCAiREJfZmlyc3RfY2hlY2siLCAiZGF0YSIsICJjbGVhbiIsImRiX0V1cm9wYV8yMDI1MDEwNy5jc3YiKQ0KICApDQpgYGANCg0KIyBTYW1wbGUgZGJfRXVyb3BhDQoNCiMjIFJlYWQgZmlsZSBkYl9yZXN1cnZfdXBkYXRlZF9jbGVhbg0KDQpUaGlzIGlzIHRoZSBSZVN1cnZleSBkYXRhYmFzZSBhZnRlciB1cGRhdGVzICh0byBiZSBjb250aW51ZWQpLg0KDQpgYGB7cn0NCmRiX3Jlc3VydiA8LSByZWFkX3RzdigNCiAgaGVyZSgiLi4iLCAiREJfZmlyc3RfY2hlY2siLCJkYXRhIiwgImNsZWFuIiwiZGJfcmVzdXJ2X3VwZGF0ZWRfY2xlYW4uY3N2IiksDQogIGNvbF90eXBlcyA9IGNvbHMoDQogICAgIyBEeW5hbWljYWxseSBzcGVjaWZ5IEVVTklTIGNvbHVtbnMgYXMgY2hhcmFjdGVyDQogICAgLmRlZmF1bHQgPSBjb2xfZ3Vlc3MoKSwgICMgRGVmYXVsdCBndWVzc2luZyBmb3Igb3RoZXIgY29sdW1ucw0KICAgIEVVTklTYSA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2IgPSBjb2xfY2hhcmFjdGVyKCksDQogICAgRVVOSVNjID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEVVTklTZCA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2FfMSA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2FfMiA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2FfMyA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2FfNCA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2JfMSA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2JfMiA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2JfMyA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2JfNCA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2NfMSA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2NfMiA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2NfMyA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2NfNCA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2RfMSA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2RfMiA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2RfMyA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2RfNCA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2FfMV9kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2JfMV9kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2NfMV9kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2RfMV9kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU19hc3NpZ25hdGlvbiA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2FfMl9kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2FfM19kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2FfNF9kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2JfMl9kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2JfM19kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2JfNF9kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2NfMl9kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2NfM19kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2NfNF9kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2RfMl9kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2RfM19kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBFVU5JU2RfNF9kZXNjciA9IGNvbF9jaGFyYWN0ZXIoKQ0KICAgICkNCiAgKQ0KYGBgDQoNCk5vIHBhcnNpbmcgaXNzdWVzIQ0KDQpHZXQgc2FtcGxlIG9mIFJlU3VydmV5IGRhdGFiYXNlOg0KDQpgYGB7cn0NCmRiX0V1cm9wYV9zYW1wbGUgPC0gbGVmdF9qb2luKA0KICBkYl9yZXN1cnYgJT4lDQogICAgc2VsZWN0KFBsb3RPYnNlcnZhdGlvbklELCBSU19DT0RFLCBgUmVTdXJ2ZXkgc2l0ZWAsIGBSZVN1cnZleSBwbG90YCwNCiAgICAgICAgICAgTG9uX3VwZGF0ZWQsTGF0X3VwZGF0ZWQsIHllYXIsZGF0ZSwNCiAgICAgICAgICAgc3RhcnRzX3dpdGgoIkVVTklTIiksIGBMb2NhdGlvbiBtZXRob2RgKSAlPiUNCiAgICBzZWxlY3QoLUVVTklTX2Fzc2lnbmF0aW9uKSwNCiAgZGJfRXVyb3BhICU+JQ0KICAgIHNlbGVjdChQbG90T2JzZXJ2YXRpb25JRCwgTG9uX3VwZGF0ZWQsIExhdF91cGRhdGVkLCB5ZWFyLCBvYnNfdW5pcXVlX2lkKQ0KKQ0KICANCnByaW50KGRiX0V1cm9wYV9zYW1wbGUsIHdpZHRoID0gSW5mKQ0KYGBgDQoNCkFkZCBjb2x1bW4gUExPVCB0byBkYXRhIHRvIGlkZW50aWZ5IHVuaXF1ZSBwbG90czoNCg0KYGBge3J9DQpkYl9FdXJvcGFfc2FtcGxlIDwtIGRiX0V1cm9wYV9zYW1wbGUgJT4lDQogICMgT3JpZ2luYWwgbmFtZXMgZ2l2ZSBwcm9ibGVtcywgY3JlYXRlIG5ldyB2YXJzDQogIG11dGF0ZShSU19zaXRlID0gYFJlU3VydmV5IHNpdGVgLCBSU19wbG90ID0gYFJlU3VydmV5IHBsb3RgKSAlPiUNCiAgIyBDb252ZXJ0IHRvIGRhdGEudGFibGUgZm9yIGZhc3RlciBwcm9jZXNzaW5nDQogIGxhenlfZHQoKSAlPiUNCiAgIyBHcm91cCBieSB0aGUgMyB2YXJzIHRoYXQgdW5pcXVlbHkgaWRlbnRpZnkgZWFjaCBwbG90DQogIGdyb3VwX2J5KFJTX0NPREUsIFJTX3NpdGUsIFJTX3Bsb3QpICU+JQ0KICAjIENyZWF0ZSBhIG5ldyB2YXJpYWJsZSBQTE9UIGZvciBlYWNoIGdyb3VwDQogIG11dGF0ZShQTE9UID0gLkdSUCkgJT4lDQogICMgQ29udmVydCBiYWNrIHRvIHRpYmJsZQ0KICBhc190aWJibGUoKSAlPiUNCiAgIyBSZW1vdmUgdW5uZWVkZWQgdmFycw0KICBzZWxlY3QoLVJTX3NpdGUsIC1SU19wbG90KQ0KYGBgDQoNCktlZXAgb25seSBoYWJpdGF0cyBGLCBSLCBTIGFuZCBRLCBhbmQsIGZvciBlYWNoIFBMT1QsIGtlZXAgb25seSB0aGUgbGFzdCByZXN1cnZleToNCg0KYGBge3J9DQpkYl9FdXJvcGFfc2FtcGxlX2xhdGVzdCA8LSBkYl9FdXJvcGFfc2FtcGxlICU+JQ0KICBmaWx0ZXIoRVVOSVNhXzEgJWluJSBjKCJUIiwgIlIiLCAiUyIsICJRIikpICU+JQ0KICBncm91cF9ieShQTE9UKSAlPiUNCiAgZmlsdGVyKGRhdGUgPT0gbWF4KGRhdGUpKSAlPiUNCiAgdW5ncm91cCgpDQpgYGANCg0KU2F2ZSBhcyBjc3YgZm9yIEJlYToNCg0KYGBge3J9DQp3cml0ZV9jc3YoZGJfRXVyb3BhX3NhbXBsZV9sYXRlc3QsDQogICAgICAgICAgZmlsZSA9ICJkYXRhL2NsZWFuL2RiX0V1cm9wYV9zYW1wbGVfbGF0ZXN0LmNzdiIpDQpgYGANCg0KU2F2ZSBhcyBzaHAgdG8gbWVyZ2Ugd2l0aCBiaW9yZWdpb25zOg0KDQpgYGB7cn0NCiMgIyBDb252ZXJ0IHRvIHNmIG9iamVjdA0KIyBkYl9FdXJvcGFfc2FtcGxlX2xhdGVzdF9zZiA8LSBzdF9hc19zZihkYl9FdXJvcGFfc2FtcGxlX2xhdGVzdCwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29vcmRzID0gYygiTG9uX3VwZGF0ZWQiLCAiTGF0X3VwZGF0ZWQiKSwgDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNycyA9IDQzMjYpICMgV0dTODQNCiMgc3Rfd3JpdGUoZGJfRXVyb3BhX3NhbXBsZV9sYXRlc3Rfc2YsDQojICAgICAgICAgICJDOi9HSVMvTU9USVZBVEUvc2hhcGVmaWxlcy9kYl9FdXJvcGFfc2FtcGxlX2xhdGVzdF9zZi5zaHAiKQ0KYGBgDQoNCiMgTWVyZ2UgUlMgZGF0YSBhbmQgZGJfRXVyb3BhX3NhbXBsZV9sYXRlc3QNCg0KR2V0IG9ubHkgdGhlIGNvbHVtbnMgUGxvdE9ic2VydmF0aW9uSUQgKG9yaWdpbmFsIHVuaXF1ZSBpZGVudGlmaWVyKSBhbmQgb2JzX3VuaXF1ZV9pZCAodW5pcXVlIGlkZW50aWZpZWQgY3JlYXRlZCBieSBtZSkuDQoNCmBgYHtyfQ0KZGJfRXVyb3BhX3NhbXBsZV9sYXRlc3QgPC0gZGJfRXVyb3BhX3NhbXBsZV9sYXRlc3QgJT4lDQogIHNlbGVjdChQbG90T2JzZXJ2YXRpb25JRCwgb2JzX3VuaXF1ZV9pZCkNCmBgYA0KDQpgYGB7cn0NCmRhdGFfUlNfUzJfSUQgPC0gZGJfRXVyb3BhX3NhbXBsZV9sYXRlc3QgJT4lDQogIHJpZ2h0X2pvaW4oZGF0YV9SU19TMiAlPiUNCiAgICAgICAgICAgICAgICMgUmVuYW1lIHRvIGJlIGFibGUgdG8gam9pbiBvbiB0aGlzIGNvbHVtbg0KICAgICAgICAgICAgICAgcmVuYW1lKFBsb3RPYnNlcnZhdGlvbklEID0gUGxvdE9ic2VydikpDQpgYGANCg0KTm93IHdlIGhhdmUgUGxvdE9ic2VydmF0aW9uSUQgaW4gZGF0YV9SU19TMl9JRC4NCg0KYGBge3J9DQojIGRhdGFfUlNfUzJfcGhlbl9JRCA8LSBkYl9FdXJvcGFfc2FtcGxlX2xhdGVzdCAlPiUNCiMgICByaWdodF9qb2luKGRhdGFfUlNfUzJfcGhlbiAlPiUNCiMgICAgICAgICAgICAgICAjIFJlbmFtZSB0byBiZSBhYmxlIHRvIGpvaW4gb24gdGhpcyBjb2x1bW4NCiMgICAgICAgICAgICAgICAgcmVuYW1lKFBsb3RPYnNlcnZhdGlvbklEID0gUGxvdE9ic2VydikpDQpgYGANCg0KTm93IHdlIGhhdmUgUGxvdE9ic2VydmF0aW9uSUQgaW4gZGF0YV9SU19TMl9waGVuX0lEDQoNCmBgYHtyfQ0KZGF0YV9SU19MYW5kc2F0X0lEIDwtIGRiX0V1cm9wYV9zYW1wbGVfbGF0ZXN0ICU+JQ0KICByaWdodF9qb2luKGRhdGFfUlNfTGFuZHNhdCAlPiUNCiAgICAgICAgICAgICAgICMgUmVuYW1lIHRvIGJlIGFibGUgdG8gam9pbiBvbiB0aGlzIGNvbHVtbg0KICAgICAgICAgICAgICAgcmVuYW1lKFBsb3RPYnNlcnZhdGlvbklEID0gUGxvdE9ic2VydikpDQpgYGANCg0KTm93IHdlIGhhdmUgUGxvdE9ic2VydmF0aW9uSUQgaW4gZGF0YV9SU19MYW5kc2F0X0lELg0KDQpgYGB7cn0NCmRhdGFfUlNfQ0hfSUQgPC0gZGJfRXVyb3BhICU+JQ0KICBzZWxlY3QoUGxvdE9ic2VydmF0aW9uSUQsIG9ic191bmlxdWVfaWQpICU+JQ0KICByaWdodF9qb2luKGRhdGFfUlNfQ0ggJT4lDQogICAgICAgICAgICAgICMgUmVuYW1lIHRvIGJlIGFibGUgdG8gam9pbiBvbiB0aGlzIGNvbHVtbg0KICAgICAgICAgICAgICByZW5hbWUob2JzX3VuaXF1ZV9pZCA9IG9ic191bmlxdWUpKQ0KYGBgDQoNCk5vdyB3ZSBoYXZlIFBsb3RPYnNlcnZhdGlvbklEIGluIGRhdGFfUlNfQ0hfSUQuDQoNCiMgTWVyZ2UgUlMgZGF0YSB0byB0aGUgUmVTdXJ2ZXkgZGF0YWJhc2UNCg0KRm9yIHNvbWUgcG9pbnRzLCB0aGVyZSBpcyBkYXRhIGJvdGggZnJvbSBTMiBhbmQgTGFuZHNhdC4gSW4gdGhvc2UgY2FzZXMsIHVzZSB0aGUgUzIgZGF0YSBiZWNhdXNlIGl0IGlzIG1vcmUgcHJlY2lzZSAoMTAgbSB2cyAzMCBtKS4NCg0KYGBge3J9DQpkYXRhX1JTX1MyX0lEIDwtIGRhdGFfUlNfUzJfSUQgJT4lDQogIHJlbmFtZV93aXRoKH4gcGFzdGUwKC4sICJfUzIiKSwgc3RhcnRzX3dpdGgoIk5EVkkiKSkgJT4lDQogIHJlbmFtZV93aXRoKH4gcGFzdGUwKC4sICJfUzIiKSwgc3RhcnRzX3dpdGgoIk5ETUkiKSkgJT4lDQogIHJlbmFtZV93aXRoKH4gcGFzdGUwKC4sICJfUzIiKSwgc3RhcnRzX3dpdGgoIk5EV0kiKSkgJT4lDQogIHJlbmFtZV93aXRoKH4gcGFzdGUwKC4sICJfUzIiKSwgc3RhcnRzX3dpdGgoIkVWSSIpKSAlPiUNCiAgcmVuYW1lX3dpdGgofiBwYXN0ZTAoLiwgIl9TMiIpLCBzdGFydHNfd2l0aCgiU0FWSSIpKSAlPiUNCiAgc2VsZWN0KC1zb3VyY2UpDQpkYXRhX1JTX0xhbmRzYXRfSUQgPC0gZGF0YV9SU19MYW5kc2F0X0lEICU+JQ0KICByZW5hbWVfd2l0aCh+IHBhc3RlMCguLCAiX0xhbmRzYXQiKSwgc3RhcnRzX3dpdGgoIk5EVkkiKSkgJT4lDQogIHJlbmFtZV93aXRoKH4gcGFzdGUwKC4sICJfTGFuZHNhdCIpLCBzdGFydHNfd2l0aCgiTkRNSSIpKSAlPiUNCiAgcmVuYW1lX3dpdGgofiBwYXN0ZTAoLiwgIl9MYW5kc2F0IiksIHN0YXJ0c193aXRoKCJORFdJIikpICU+JQ0KICByZW5hbWVfd2l0aCh+IHBhc3RlMCguLCAiX0xhbmRzYXQiKSwgc3RhcnRzX3dpdGgoIkVWSSIpKSAlPiUNCiAgcmVuYW1lX3dpdGgofiBwYXN0ZTAoLiwgIl9MYW5kc2F0IiksIHN0YXJ0c193aXRoKCJTQVZJIikpICU+JQ0KICBzZWxlY3QoLXNvdXJjZSkNCmBgYA0KDQpKb2luIFMyLCBTMl9waGVuIGFuZCBMYW5kc2F0IGRhdGE6DQoNCmBgYHtyfQ0KZGF0YV9SUyA8LSBkYXRhX1JTX1MyX0lEICU+JSANCiAgIyBmdWxsX2pvaW4oZGF0YV9SU19TMl9waGVuX0lEKSAlPiUNCiAgZnVsbF9qb2luKGRhdGFfUlNfTGFuZHNhdF9JRCkNCmBgYA0KDQpOdW1iZXIgb2Ygb2JzZXJ2YXRpb25zIHdpdGggTkRWSV9tYXggZGF0YSBmcm9tIGJvdGggUzIgYW5kIExhbmRzYXQ6DQoNCmBgYHtyfQ0KbnJvdyhkYXRhX1JTICU+JSBmaWx0ZXIoIWlzLm5hKE5EVklfbWF4X1MyKSAmICFpcy5uYShORFZJX21heF9MYW5kc2F0KSkpDQpgYGANCg0KRGlmZmVyZW5jZSBiZXR3ZWVuIE5EVklfbWF4IHZhbHVlcyBmcm9tIFMyIGFuZCBMYW5kc2F0Og0KDQpgYGB7cn0NCmRhdGFfUlMgJT4lIGZpbHRlcighaXMubmEoTkRWSV9tYXhfUzIpICYgIWlzLm5hKE5EVklfbWF4X0xhbmRzYXQpKSAlPiUNCiAgbXV0YXRlKGRpZmZfTkRWSV9tYXggPSBhYnMoTkRWSV9tYXhfUzIgLSBORFZJX21heF9MYW5kc2F0KSkgJT4lDQogIGdncGxvdChhZXMoeCA9IGRpZmZfTkRWSV9tYXgsIGZpbGwgPSBwYXN0ZShiaW9nZW8sIHVuaXQsIHNlcCA9ICItIikpKSArDQogIGdlb21faGlzdG9ncmFtKGNvbG9yID0gImJsYWNrIikgKyANCiAgZmFjZXRfd3JhcCh+IHBhc3RlKGJpb2dlbywgdW5pdCwgc2VwID0gIi0iKSkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpkYXRhX1JTICU+JSBmaWx0ZXIoIWlzLm5hKE5ETUlfbWF4X1MyKSAmICFpcy5uYShORE1JX21heF9MYW5kc2F0KSkgJT4lDQogIG11dGF0ZShkaWZmX05ETUlfbWF4ID0gYWJzKE5ETUlfbWF4X1MyIC0gTkRNSV9tYXhfTGFuZHNhdCkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBkaWZmX05ETUlfbWF4LCBmaWxsID0gcGFzdGUoYmlvZ2VvLCB1bml0LCBzZXAgPSAiLSIpKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShjb2xvciA9ICJibGFjayIpICsgDQogIGZhY2V0X3dyYXAofiBwYXN0ZShiaW9nZW8sIHVuaXQsIHNlcCA9ICItIikpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNClRoZXJlIGlzIGEgbGFyZ2UgZGlmZmVyZW5jZSBiZXR3ZWVuIE5EVkkgdmFsdWVzIGZyb20gUzIgYW5kIExhbmRzYXQuIFNvIGZhciwgdXNlIHRoZSBTMiBkYXRhLCBidXQgY2hlY2tpbmcgd2l0aCBCZWEgLyBKb3NlLg0KDQpXaGVuIHZhbHVlcyBhcmUgYXZhaWxhYmxlIGZyb20gYm90aCBzYXRlbGxpdGVzLCB1c2UgUzI6DQoNCmBgYHtyfQ0KZGF0YV9SUyA8LSBkYXRhX1JTICU+JQ0KICBtdXRhdGUoYWNyb3NzKA0KICAgIG1hdGNoZXMoIl4oTkRWSXxORE1JfE5EV0l8RVZJfFNBVkkpXyhtYXh8bWVhbnxtZWRpYW58bWlufG1vZGV8cDEwfHA5MHxzdGREZXYpX1MyJCIpLA0KICAgIH4gY2FzZV93aGVuKA0KICAgICAgIyBJZiBib3RoIHRoZSBjdXJyZW50IGNvbHVtbiBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgTGFuZHNhdCBjb2x1bW4gYXJlIE5BLA0KICAgICAgIyBzZXQgdG8gTkFfcmVhbF8NCiAgICAgIGlzLm5hKC54KSAmIGlzLm5hKGdldChzdWIoIl9TMiQiLCAiX0xhbmRzYXQiLCBjdXJfY29sdW1uKCkpKSkgfiBOQV9yZWFsXywNCiAgICAgICMgSWYgdGhlIGNvcnJlc3BvbmRpbmcgTGFuZHNhdCBjb2x1bW4gaXMgTkEsIHVzZSB0aGUgY3VycmVudCBjb2x1bW4ncyB2YWx1ZQ0KICAgICAgaXMubmEoZ2V0KHN1YigiX1MyJCIsICJfTGFuZHNhdCIsIGN1cl9jb2x1bW4oKSkpKSB+IC54LA0KICAgICAgIyBJZiB0aGUgY3VycmVudCBjb2x1bW4gaXMgTkEsIHVzZSB0aGUgY29ycmVzcG9uZGluZyBMYW5kc2F0IGNvbHVtbidzIHZhbHVlDQogICAgICBpcy5uYSgueCkgfiBnZXQoc3ViKCJfUzIkIiwgIl9MYW5kc2F0IiwgY3VyX2NvbHVtbigpKSksDQogICAgICAjIE90aGVyd2lzZSwgdXNlIHRoZSBjdXJyZW50IGNvbHVtbidzIHZhbHVlDQogICAgICBUUlVFIH4gLngNCiAgICAgICksIC5uYW1lcyA9ICJ7Y29sfV9jb21iaW5lZCIpKSAlPiUNCiAgcmVuYW1lX3dpdGgofiBzdWIoIl9TMl9jb21iaW5lZCQiLCAiIiwgLiksIG1hdGNoZXMoIl9TMl9jb21iaW5lZCQiKSkNCmBgYA0KDQpHZXQgbnVtYmVyIG9mIHBvaW50cyBwZXIgYmlvZ2VvIGFuZCB1bml0Og0KDQpgYGB7cn0NCm5wb2ludHNfYmlvcmVnaW9uX1IgPC0gZGF0YV9SUyAlPiUgY291bnQoYmlvZ2VvLCB1bml0KSAlPiUNCiAgbXV0YXRlKG5wb2ludHNfUiA9IG4pICU+JQ0KICBzZWxlY3QoLW4pDQpgYGANCg0KUmVhZCBudW1iZXIgb2YgcG9pbnRzIHBlciBiaW9nZW8gYW5kIHVuaXQgZnJvbSBHSVM6DQoNCmBgYHtyfQ0KbnBvaW50c19iaW9yZWdpb25fR0lTIDwtIHJlYWRfZGVsaW0oDQogICJkYXRhL2NsZWFuL05wb2ludHNfYmlvcmVnaW9uLmNzdiIsIGRlbGltID0gIjsiDQogICkgJT4lDQogIHNlbGVjdCAoQklPR0VPLCBVTklULCBKb2luX0NvdW50KSAlPiUNCiAgbXV0YXRlKGJpb2dlbyA9IEJJT0dFTywgdW5pdCA9IHN0cl9yZW1vdmUoVU5JVCwgQklPR0VPKSwNCiAgICAgICAgIG5wb2ludHNfR0lTID0gSm9pbl9Db3VudCkgJT4lDQogIG11dGF0ZShiaW9nZW8gPSBpZmVsc2UoYmlvZ2VvID09ICJQQU4iLCAiUEFOT05JQSIsIGJpb2dlbykpICU+JQ0KICBtdXRhdGUodW5pdCA9IGlmZWxzZShiaW9nZW8gPT0gIlBBTk9OSUEiLCBOQSwgdW5pdCkpICU+JQ0KICBzZWxlY3QoLSBCSU9HRU8sIC0gVU5JVCwgLUpvaW5fQ291bnQpDQpgYGANCg0KTWVyZ2UgYm90aCBhbmQgc2VlIGRpZmZlcmVuY2VzIGluIG4gcG9pbnRzOg0KDQpgYGB7cn0NCm5wb2ludHNfYmlvcmVnaW9uX21lcmdlZCA8LSBmdWxsX2pvaW4obnBvaW50c19iaW9yZWdpb25fUiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnBvaW50c19iaW9yZWdpb25fR0lTKQ0KYGBgDQoNCk5pY2UgdGFibGUgdG8gZW1haWwgdG8gQmVhOg0KDQpgYGB7cn0NCmthYmxlKHByaW50KG5wb2ludHNfYmlvcmVnaW9uX21lcmdlZCAlPiUgYXJyYW5nZShiaW9nZW8sIHVuaXQpLCBuID0gMTAwKSkNCmBgYA0KDQoNCg0KYGBge3J9DQpkYl9yZXN1cnZfUlMgPC0gZGJfcmVzdXJ2ICU+JQ0KICBsZWZ0X2pvaW4oZGF0YV9SUyAlPiUgc2VsZWN0KC1vYnNfdW5pcXVlX2lkKSkgJT4lDQogIGxlZnRfam9pbihkYXRhX1JTX0NIX0lEICU+JSBzZWxlY3QoLW9ic191bmlxdWVfaWQpKSAlPiUNCiAgbXV0YXRlKFMyX2RhdGEgPSAhaXMubmEoTkRWSV9tYXhfUzIpICYgIWlzLm5hKE5ETUlfbWF4X1MyKSwgDQogICAgICAgICBMYW5kc2F0X2RhdGEgPSAhaXMubmEoTkRWSV9tYXhfTGFuZHNhdCkgJiAhaXMubmEoTkRNSV9tYXhfTGFuZHNhdCksDQogICAgICAgICBTMl9vcl9MYW5kc2F0X2RhdGEgPSAhaXMubmEoTkRWSV9tYXgpICYgIWlzLm5hKE5ETUlfbWF4KSwgDQogICAgICAgICAjIFMyX3BoZW5fZGF0YSA9ICFpcy5uYShTT1NfRE9ZKSwNCiAgICAgICAgIENIX2RhdGEgPSAhaXMubmEoY2Fub3B5X2hlaWdodCkpICU+JQ0KICAjIFNvIGZhciwgcmVtb3ZlIGNvbHMgZm9yIF9TMiBhbmQgX0xhbmRzYXQNCiAgc2VsZWN0KC1tYXRjaGVzKCJfKFMyfExhbmRzYXQpJCIpKQ0KYGBgDQoNCmBgYHtyfQ0KZGJfcmVzdXJ2X1JTICU+JSBjb3VudChTMl9kYXRhKQ0KZGJfcmVzdXJ2X1JTICU+JSBjb3VudChMYW5kc2F0X2RhdGEpDQpkYl9yZXN1cnZfUlMgJT4lIGNvdW50KFMyX29yX0xhbmRzYXRfZGF0YSkNCmRiX3Jlc3Vydl9SUyAlPiUgY291bnQoQ0hfZGF0YSkNCiMgZGJfcmVzdXJ2X1JTICU+JSBjb3VudChTMl9waGVuX2RhdGEpDQpgYGANCg0KIyBTYXZlIHRvIGNsZWFuIGRhdGENCg0KU2F2ZSBjbGVhbiBmaWxlIGZvciBhbmFseXNlcyAodG8gYmUgdXBkYXRlZCBjb250aW51b3VzbHkgZHVlIHRvIHVwZGF0ZXMgaW4gUmVTdXJ2ZXkgZGF0YWJhc2UgYW5kIHVwZGF0ZXMgb24gUlMgZGF0YSkuDQoNCmBgYHtyfQ0Kd3JpdGVfdHN2KGRiX3Jlc3Vydl9SUyxoZXJlKCJkYXRhIiwgImNsZWFuIiwiZGJfcmVzdXJ2X1JTXzIwMjUwNjEwLmNzdiIpKQ0KYGBgDQoNCiMgU2Vzc2lvbiBpbmZvDQoNCmBgYHtyfQ0Kc2Vzc2lvbkluZm8oKQ0KYGBgDQo=